/**
 * 
 */
package com.ms.service.module.baccarat;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ms.player.Player;
import com.ms.player.PlayerUserType;
import com.ms.service.error.ErrorCode;
import com.ms.service.module.baccarat.bin.BacrBetType;
import com.xpec.c4.game.datamanager.agent.money.CoinType;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.message.ConstantCode;

/**
 * 玩家押注階段的資料
 * 
 * @author TW15010
 */
public class BacrPlayerBetStep {
	/** log4j object */
	private static final Log log = LogFactory.getLog(BacrPlayerBetStep.class);

	/**
	 * 押閒家
	 * <p>
	 * key: 玩家 guid<br>
	 * value: 押注金額
	 */
	private HashMap<GUID, Integer> playerMap = new HashMap<GUID, Integer>();

	/**
	 * 押莊家
	 * <p>
	 * key: 玩家 guid<br>
	 * value: 押注金額
	 */
	private HashMap<GUID, Integer> bankerMap = new HashMap<GUID, Integer>();

	/**
	 * 押和
	 * <p>
	 * key: 玩家 guid<br>
	 * value: 押注金額
	 */
	private HashMap<GUID, Integer> tieMap = new HashMap<GUID, Integer>();

	/**
	 * 押閒對
	 * <p>
	 * key: 玩家 guid<br>
	 * value: 押注金額
	 */
	private HashMap<GUID, Integer> playerPairMap = new HashMap<GUID, Integer>();

	/**
	 * 押莊對
	 * <p>
	 * key: 玩家 guid<br>
	 * value: 押注金額
	 */
	private HashMap<GUID, Integer> bankerPairMap = new HashMap<GUID, Integer>();

	/**
	 * 所有投注玩家的 order id map
	 * <p>
	 * key: 玩家 guid<br>
	 * value: 押注玩家的基本資訊
	 */
	private HashMap<GUID, BacrBetPlayerInfo> betPlayerInfoMap = new HashMap<GUID, BacrBetPlayerInfo>();

	/**
	 * 押注送到 dc 處理的次數
	 */
	private int betToDcCount;

	/**
	 * 成功押注的次數
	 */
	private int betSuccessCount;

	/**
	 * 押注階段開始時牌靴內是否為紅卡
	 */
	private boolean redCardInShoeWhenBegin;

	/**
	 * 增加玩家押注資料
	 * <p>
	 * 如果已經存在的資料就會被覆蓋
	 * 
	 * @param playerId
	 *            玩家 id
	 * @param betType
	 *            押注類型 {@link BacrBetType}
	 * @param betValue
	 *            押注金額
	 * @return
	 */
	public int setBetInfo(GUID playerId, int betType, int betValue) {
		if (playerId == null) {
			return ErrorCode.INVALID_PLAYER_ID;
		}

		// 取對應的資料 map
		HashMap<GUID, Integer> dataMap = getDataMap(betType);
		if (dataMap == null) {
			return ErrorCode.BACR_INVALID_BET_TYPE;
		}

		if (betValue <= 0) {
			return ErrorCode.INVALID_BET_MONEY;
		}

		dataMap.put(playerId, betValue);

		if (log.isInfoEnabled()) {
			log.info("player " + playerId + " add bet " + ConstantCode.getName(BacrBetType.class, betType)
					+ " value=" + betValue);
		}

		return ErrorCode.SUCCESS;
	}

	/**
	 * 取得指定玩家在指定部位的押注金額
	 * 
	 * @param playerId
	 * @param betType
	 *            {@link BacrBetType}
	 * @return
	 */
	public BigDecimal getBetValue(GUID playerId, int betType) {
		HashMap<GUID, Integer> dataMap = getDataMap(betType);
		if (dataMap == null) {
			return BigDecimal.ZERO;
		}

		if (dataMap.containsKey(playerId)) {
			int betValue = dataMap.get(playerId);
			return new BigDecimal(betValue);
		}

		return BigDecimal.ZERO;
	}

	/**
	 * 取得押注類型對應的 data map
	 * 
	 * @param betType
	 *            押注類型 {@link BacrBetType}
	 * @return
	 */
	public HashMap<GUID, Integer> getDataMap(int betType) {
		HashMap<GUID, Integer> dataMap = null;

		switch (betType) {
		case BacrBetType.PLAYER:
			dataMap = playerMap;
			break;
		case BacrBetType.BANKER:
			dataMap = bankerMap;
			break;
		case BacrBetType.TIE:
			dataMap = tieMap;
			break;
		case BacrBetType.PLAYER_PAIR:
			dataMap = playerPairMap;
			break;
		case BacrBetType.BANKER_PAIR:
			dataMap = bankerPairMap;
			break;
		default:
			if (log.isErrorEnabled()) {
				GameUtility.logErrorException(log, "invalid betType " + betType);
			}
			return new HashMap<GUID, Integer>();
		}

		return dataMap;
	}

	/**
	 * 設定押注玩家的簡易資訊
	 * 
	 * @param player
	 *            player data
	 * @param coinType
	 *            幣別
	 * @param playerBeforeMoney
	 *            牌局開始前的錢
	 * @param orderId
	 *            order id
	 */
	public void setBetPlayerInfo(Player player, CoinType coinType, BigDecimal playerBeforeMoney, GUID orderId) {
		if (player == null) {
			if (log.isErrorEnabled()) {
				GameUtility.logErrorException(log, "player = null");
			}
			return;
		}

		if (orderId == null) {
			if (log.isErrorEnabled()) {
				GameUtility.logErrorException(log, "orderId = null");
			}
			return;
		}

		BacrBetPlayerInfo info = new BacrBetPlayerInfo();
		info.setAccountId(player.getAccountId());
		info.setPlayerId(player.getGuid());
		info.setPlayerName(player.getNameWithNumber());
		info.setOrderId(orderId);
		info.setUserType(player.getUserType());
		info.setCoinType(coinType);
		info.setBeforeMoney(playerBeforeMoney);

		betPlayerInfoMap.put(player.getGuid(), info);
	}

	/**
	 * 是否有指定玩家的 order id
	 * 
	 * @param playerId
	 * @return
	 */
	public boolean isPlayerHaveOrderId(GUID playerId) {
		return betPlayerInfoMap.containsKey(playerId);
	}

	/**
	 * 取得指定押注玩家的基本資訊
	 * 
	 * @param playerId
	 * @return
	 */
	public BacrBetPlayerInfo getBetPlayerInfo(GUID playerId) {
		return betPlayerInfoMap.get(playerId);
	}

	/**
	 * 清除指定玩家的押注資訊
	 * 
	 * @param playerId
	 */
	public void removePlayerBetInfo(GUID playerId) {
		playerMap.remove(playerId);
		bankerMap.remove(playerId);
		tieMap.remove(playerId);
		playerPairMap.remove(playerId);
		bankerPairMap.remove(playerId);
		betPlayerInfoMap.remove(playerId);
	}

	public void clear() {
		playerMap.clear();
		bankerMap.clear();
		tieMap.clear();
		playerPairMap.clear();
		bankerPairMap.clear();
		betPlayerInfoMap.clear();

		betToDcCount = 0;
		betSuccessCount = 0;

		redCardInShoeWhenBegin = false;
	}

	public HashMap<GUID, BacrBetPlayerInfo> getBetPlayerInfoMap() {
		return betPlayerInfoMap;
	}

	/**
	 * 取得指定部位的總押注金額
	 * 
	 * @param betType
	 *            押注類型 {@link BacrBetType}
	 * @return
	 */
	public long getTotalBetByBetType(int betType) {
		HashMap<GUID, Integer> dataMap = getDataMap(betType);

		long totalBet = 0;

		for (Entry<GUID, Integer> entry : dataMap.entrySet()) {
			long betValue = entry.getValue().longValue();
			totalBet += betValue;
		}

		return totalBet;
	}

	/**
	 * 取得押注的玩家數量
	 * 
	 * @param userType
	 *            玩家類型 {@link PlayerUserType}
	 * @return
	 */
	public int getBetPlayerCount(int userType) {
		int count = 0;

		for (Entry<GUID, BacrBetPlayerInfo> entry : betPlayerInfoMap.entrySet()) {
			BacrBetPlayerInfo info = entry.getValue();
			if (info.getUserType() == userType) {
				count++;
			}
		}

		return count;
	}

	public int getBetToDcCount() {
		return betToDcCount;
	}

	public int getBetSuccessCount() {
		return betSuccessCount;
	}

	public void increaseBetToDcCount() {
		betToDcCount++;
	}

	public void increaseBetSuccessCount() {
		betSuccessCount++;
	}

	public boolean isRedCardInShoeWhenBegin() {
		return redCardInShoeWhenBegin;
	}

	public void setRedCardInShoeWhenBegin(boolean redCardInShoeWhenBegin) {
		this.redCardInShoeWhenBegin = redCardInShoeWhenBegin;
	}
}
